; 需在支持直接系统调用的环境中使用，系统调用号需根据Windows版本调整
; 当前程序在 Windows 10 X64 企业版 22H2 测试通过

section .data
    msg db 'Hello World!', 0
    msglen equ $ - msg - 1  ; 计算字符串长度（不包括终止符）
    bytesWritten dd 0                             ; 保存实际写入字节数

section .text
    global Start
    extern GetStdHandle                           ; 声明外部 API 函数
    extern WriteFile
    extern ExitProcess
Start:
    ;sub rsp, 40                                   ; 调整栈对齐（32字节影子空间 + 8字节对齐）
    ; 1. 获取标准输出句柄（STD_OUTPUT_HANDLE = -11）
    ;mov rcx, -11                                  ; 参数1：STD_OUTPUT_HANDLE
    ;call GetStdHandle

    ; 1.1. 获取 PEB 地址
    mov rax, gs:[0x60]        ; GS 寄存器指向 TEB，TEB+0x60 是 PEB 地址
    ; 1.2. 定位到 PEB.ProcessParameters
    mov rax, [rax + 0x20]     ; PEB+0x20 是 ProcessParameters 指针
    ; 1.3. 读取 StdOutputHandle
    mov rax, [rax + 0x28]     ; ProcessParameters+0x28 是 StdOutputHandle

    cmp rax, -1                                   ; 检查是否无效（INVALID_HANDLE_VALUE）
    je error

    ; 2. 调用 WriteFile 写入内容
    ;mov rbx, rax                                  ; 保存句柄到 rbx
    ;mov rcx, rbx                                  ; 参数1：hFile（标准输出句柄）
    ;lea rdx, [rel msg]                            ; 参数2：lpBuffer（字符串地址）
    ;mov r8, msglen                                ; 参数3：nNumberOfBytesToWrite
    ;lea r9, [rel bytesWritten]                    ; 参数4：lpNumberOfBytesWritten
    ;mov qword [rsp + 32], 0                       ; 参数5：lpOverlapped = NULL（栈上第五参数）
    ;call WriteFile

    ;jmp ExitProcess
    ; 2.  NtWriteFile 准备参数
    ;   - FileHandle: RAX 中已有
    ;   - Event: NULL
    ;   - ApcRoutine: NULL
    ;   - ApcContext: NULL
    ;   - IoStatusBlock: 需要在栈上分配
    ;   - Buffer: 指向 message
    ;   - Length: msg_length
    ;   - ByteOffset: NULL
    ;   - Key: NULL

    sub rsp, 0x60           ; 为系统调用参数分配空间
    and rsp, ~0x1F          ; 确保栈对齐到32字节

    mov rcx, rax            ; 第一个参数：句柄
    xor rdx, rdx            ; 第二个参数：Event = NULL
    xor r8, r8              ; 第三个参数，ApcRoutine = NULL
    xor r9, r9              ; 第四个参数，ApcContext = NULL
    
    ; 设置栈参数（从右到左，地址从高到低）
    ; 栈参数顺序：IoStatusBlock (PTR), Buffer (PTR), Length (ULONG), ByteOffset (PTR), Key (PTR)
    ; 注意：栈参数应该放在调用点的栈上，偏移基于 RSP。    

    mov qword [rsp + 0x50], 0       ; IoStatusBlock Status
    mov qword [rsp + 0x58], 0       ; IoStatusBlock Information
    lea rax, [rsp + 0x50]      ; IoStatusBlock 地址     
    mov qword [rsp + 0x28], rax ; IoStatusBlock 

    lea rax, [rel msg]
    mov qword [rsp + 0x30], rax    ; Buffer区地址
    mov qword [rsp + 0x38], msglen ; Length写入的字节数
    xor rax, rax
    mov [rsp + 0x40], rax   ; ByteOffset = NULL
    mov [rsp + 0x48], rax   ; Key = NULL
  
    ; NTWriteFile
    mov r10, rcx           ; 句柄
    mov rax, 0x8           ; 0x8 是 NtWriteFile 的系统调用号
    syscall                ; 执行系统调用

    test rax, rax           ; 检查NTSTATUS
    jnz error

    ; 正常退出
    xor rdx, rdx
    jmp ExitProcess

error:
    ; 错误退出
    mov rdx, 1

ExitProcess:  
    ; rax: 0x2c, r10 rcx: ProcessHandle, rdx: ExitStatus
    mov rcx, -1        ; ProcessHandle = -1 (当前进程)
    mov r10, rcx
    mov eax, 0x2C       ; 假设NtTerminateProcess的系统调用号是0x2C
    syscall             ; 执行系统调用

    ; 如果失败则无限循环
    jmp $
